package com.xudu.tourbackend.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.xudu.tourbackend.common.globalEnum.ErrorCode;
import com.xudu.tourbackend.entity.User;
import com.xudu.tourbackend.entity.request.SearchUserRequest;
import com.xudu.tourbackend.entity.request.UpdateUserRequest;
import com.xudu.tourbackend.entity.vo.UserVo;
import com.xudu.tourbackend.exception.ServiceException;
import com.xudu.tourbackend.mapper.UserMapper;
import com.xudu.tourbackend.service.IUserService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xudu.tourbackend.utils.AESUtil;
import com.xudu.tourbackend.utils.QiniuUtil;
import com.xudu.tourbackend.utils.RedisUtil;
import com.xudu.tourbackend.utils.SMSUtil;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import static com.xudu.tourbackend.constant.UserConstant.ADMIN_ROLE;
import static com.xudu.tourbackend.constant.UserConstant.USER_LOGIN_STATE;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author xudu
 * @since 2024-06-17
 */
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {

    @Resource
    private UserMapper userMapper;

    @Resource
    private RedisUtil redisUtil;

    @Resource
    private QiniuUtil qiniuUtil;


    @Override
    public int register(String userAccount, String userPassword, String checkUserPassword) throws Exception {
        if (StringUtils.isAnyBlank(userAccount, userPassword, checkUserPassword)) {
            throw new ServiceException(ErrorCode.PARAMS_ERROR, "账号或密码为空");
        }
        if (userAccount.length() < 4) {
            throw new ServiceException(ErrorCode.PARAMS_ERROR, "账号过短");
        }
        if (userPassword.length() < 6 || checkUserPassword.length() < 6) {
            throw new ServiceException(ErrorCode.PARAMS_ERROR, "密码过短");
        }
        if (!checkUserPassword.equals(userPassword)) {
            throw new ServiceException(ErrorCode.PARAMS_ERROR, "两次密码不一致");
        }
        // 定义用户账号正则表达式（只允许字母和数字）
        String USERNAME_REGEX = "^[a-zA-Z0-9]+$";
        // 编译正则表达式
        Pattern pattern = Pattern.compile(USERNAME_REGEX);
        // 创建匹配器
        Matcher matcher = pattern.matcher(userAccount);
        //如果用户账号包含特殊字符，返回错误
        if (!matcher.matches()) {
            throw new ServiceException(ErrorCode.PARAMS_ERROR, "账号包含特殊字符");
        }
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(User::getUseraccount, userAccount);
        Long count = userMapper.selectCount(queryWrapper);
        if (count > 0) {
            throw new ServiceException(ErrorCode.PARAMS_ERROR, "账号重复");
        }
        //密码加密todo
        String encrypt = AESUtil.encrypt(userPassword);

        //将用户信息保存数据库
        User user = new User();
        user.setUseraccount(userAccount);
        user.setUserpassword(encrypt);
        userMapper.insert(user);
        //返回新用户id
        return user.getUserid();
    }

    @Override
    public String registerByPhone(String userPhone) {
        /*
            a. 前端传入的参数:用户账号、用户密码、重复输入密码、用户手机
            b. 参数判空，校验账号密码是否合法，
            c. 正则表达式判断用户账号不包含特殊字符，用户手机符合手机号的格式
            d. 判断账号和手机号是否已注册
            e. 后端对其发送短信验证码并将验证码存储在redis，手机号是key
            f. 后端接收短信验证码，判空、判断是否符合验证码格式
            g. 后端与redis中的验证码比较是否一致
            h. 以上都符合即可注册成功，返回注册成功id
         */

        //commons-lang3包的StringUtils 可以判断一组数据是否为空
        if (StringUtils.isBlank(userPhone)) {
            throw new ServiceException(ErrorCode.PARAMS_ERROR, "手机号不能为空");
        }
        if (userPhone.length() != 11) {
            throw new ServiceException(ErrorCode.PARAMS_ERROR, "手机号格式错误");
        }
        // 定义手机号正则表达式
        String PHONE_REGEX = "^1[3-9]\\d{9}$";
        // 编译正则表达式
        Pattern pattern = Pattern.compile(PHONE_REGEX);
        // 创建匹配器
        Matcher matcher = pattern.matcher(userPhone);
        //如果手机号不符合手机号格式，返回错误
        if (!matcher.matches()) {
            throw new ServiceException(ErrorCode.PARAMS_ERROR, "手机号格式错误");
        }
        //判断该手机号是否已注册，不能重复
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(User::getUserphone, userPhone);
        User user = userMapper.selectOne(queryWrapper);
        if (user != null) {
            throw new ServiceException(ErrorCode.PARAMS_ERROR, "该手机号已注册");
        }
        //发送短信验证码
        String code = SMSUtil.sendSMSCode(userPhone);
        redisUtil.setRedisContent(userPhone, code, 300L);
        return code;
    }

    @Override
    public int verifyCode(String userPhone, String code) {
        if (StringUtils.isAnyBlank(userPhone, code)) {
            throw new ServiceException(ErrorCode.PARAMS_ERROR, "手机号或验证码为空");
        }
        if (userPhone.length() != 11) {
            throw new ServiceException(ErrorCode.PARAMS_ERROR, "手机号格式错误");
        }
        //判断验证码是否一致
        String redisContent = redisUtil.getRedisContent(userPhone);
        if (!code.equals(redisContent)) {
            throw new ServiceException(ErrorCode.PARAMS_ERROR, "验证码错误");
        }
        User user = new User();
        user.setUserphone(userPhone);
        boolean save = this.save(user);

        if (!save) {
            throw new ServiceException(ErrorCode.SYSTEM_ERROR, "注册失败");
        }
        return user.getUserid();

        //QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        //queryWrapper.lambda().eq(User::getUserphone, userPhone);
        ////User user = userMapper.selectOne(queryWrapper);
        //return user.getUserid();
    }

    //通过账号或手机号采用密码登陆
    @Override
    public UserVo login(String account, String userPassword, HttpServletRequest request) throws Exception {
        if (StringUtils.isAnyBlank(account, userPassword)) {
            throw new ServiceException(ErrorCode.PARAMS_ERROR, "账号或密码不能为空");
        }
        if (account.length() < 4) {
            throw new ServiceException(ErrorCode.PARAMS_ERROR, "账号过短");
        }
        // 定义用户账号正则表达式（只允许字母和数字）
        String USERNAME_REGEX = "^[a-zA-Z0-9]+$";
        // 定义手机号正则表达式
        String PHONE_REGEX = "^1[3-9]\\d{9}$";
        // 编译正则表达式
        Pattern patternAccount = Pattern.compile(USERNAME_REGEX);
        Pattern patternPhone = Pattern.compile(PHONE_REGEX);
        // 创建匹配器
        Matcher matcherAccount = patternAccount.matcher(account);
        Matcher matcherPhone = patternPhone.matcher(account);

        //if (!matcherAccount.matches() && !matcherPhone.matches()){
        //    return null;
        //}

        if (matcherPhone.matches()) {
            QueryWrapper<User> queryWrapperPhone = new QueryWrapper<>();
            queryWrapperPhone.lambda().eq(User::getUserphone, account);
            User user = userMapper.selectOne(queryWrapperPhone);
            if (user != null) {
                //说明查到了
                //判断密码是否匹配
                String userpassword = user.getUserpassword();
                String decrypt = AESUtil.decrypt(userpassword);
                if (!userPassword.equals(decrypt)) {
                    throw new ServiceException(ErrorCode.PARAMS_ERROR, "密码错误");
                }
                //数据脱敏todo
                UserVo userVo = new UserVo();
                BeanUtils.copyProperties(user, userVo);
                request.getSession().setAttribute(USER_LOGIN_STATE, userVo);
                return userVo;
            }

        }

        if (matcherAccount.matches()) {
            QueryWrapper<User> queryWrapperAccount = new QueryWrapper<>();
            queryWrapperAccount.lambda().eq(User::getUseraccount, account);
            User user = userMapper.selectOne(queryWrapperAccount);
            if (user != null) {
                //说明查到了
                //判断密码是否匹配
                String userpassword = user.getUserpassword();
                String decrypt = AESUtil.decrypt(userpassword);
                if (!userPassword.equals(decrypt)) {
                    throw new ServiceException(ErrorCode.PARAMS_ERROR, "密码错误");
                }
                //数据脱敏todo
                UserVo userVo = new UserVo();
                BeanUtils.copyProperties(user, userVo);
                request.getSession().setAttribute(USER_LOGIN_STATE, userVo);
                return userVo;
            }
        }

        throw new ServiceException(ErrorCode.PARAMS_ERROR, "账号不存在");

    }

    @Override
    public String loginByPhone(String userPhone) {
        if (StringUtils.isBlank(userPhone)) {
            throw new ServiceException(ErrorCode.PARAMS_ERROR, "手机号不能为空");
        }

        if (userPhone.length() < 11) {
            throw new ServiceException(ErrorCode.PARAMS_ERROR, "手机号格式错误");
        }

        String PHONE_REGEX = "^1[3-9]\\d{9}$";
        Pattern pattern = Pattern.compile(PHONE_REGEX);
        Matcher matcher = pattern.matcher(userPhone);
        if (!matcher.matches()) {
            throw new ServiceException(ErrorCode.PARAMS_ERROR, "手机号格式错误");
        }

        QueryWrapper<User> queryWrapperPhone = new QueryWrapper<>();
        queryWrapperPhone.lambda().eq(User::getUserphone, userPhone);
        User user = userMapper.selectOne(queryWrapperPhone);
        if (user == null) {
            throw new ServiceException(ErrorCode.PARAMS_ERROR, "手机号不存在");
        }

        String code = SMSUtil.sendSMSCode(userPhone);
        redisUtil.setRedisContent(userPhone, code, 300L);
        return code;


    }

    @Override
    public UserVo loginVerifyCode(String userPhone, String code, HttpServletRequest request) {
        if (StringUtils.isAnyBlank(userPhone, code)) {
            throw new ServiceException(ErrorCode.PARAMS_ERROR, "手机号或验证码不能为空");
        }

        if (code.length() != 4) {
            throw new ServiceException(ErrorCode.PARAMS_ERROR, "验证码格式错误");
        }

        String content = redisUtil.getRedisContent(userPhone);
        if (!code.equals(content)) {
            throw new ServiceException(ErrorCode.PARAMS_ERROR, "验证码错误");
        }
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(User::getUserphone, userPhone);
        User user = userMapper.selectOne(queryWrapper);
        if (user == null) {
            throw new ServiceException(ErrorCode.PARAMS_ERROR, "手机号不存在");
        }
        //数据脱敏todo
        UserVo userVo = new UserVo();
        BeanUtils.copyProperties(user, userVo);
        request.getSession().setAttribute(USER_LOGIN_STATE, userVo);
        return userVo;
    }

    @Override
    public UserVo getLoginUser(HttpServletRequest request) {
        if (request == null) {
            throw new ServiceException(ErrorCode.SYSTEM_ERROR);
        }
        Object userObj = request.getSession().getAttribute(USER_LOGIN_STATE);
        if (userObj == null) {
            throw new ServiceException(ErrorCode.NOT_LOGIN);
        }

        return (UserVo) userObj;
    }

    @Override
    public Boolean isAdmin(UserVo loginUser) {
        return (loginUser != null) && (Objects.equals(loginUser.getUserrole(), ADMIN_ROLE));
    }

    @Override
    public Boolean isAdmin(HttpServletRequest request) {
        Object userObj = request.getSession().getAttribute(USER_LOGIN_STATE);
        UserVo userVo = (UserVo) userObj;
        return userVo != null && Objects.equals(userVo.getUserrole(), ADMIN_ROLE);
    }

    @Override
    public void userLogout(HttpServletRequest request) {
        // 移除登录态
        request.getSession().removeAttribute(USER_LOGIN_STATE);
    }


    @Override
    public IPage<UserVo> searchUser(SearchUserRequest searchUserRequest, HttpServletRequest request) {
        if (!isAdmin(request)) {
            throw new ServiceException(ErrorCode.NO_AUTH);
        }

        //条件组合查询
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();

        Integer userid = searchUserRequest.getUserid();
        if (userid != null && userid > 0) {
            queryWrapper.lambda().eq(User::getUserid, userid);
        }
        String userName = searchUserRequest.getUsername();
        if (StringUtils.isNotBlank(userName)) {
            queryWrapper.lambda().like(User::getUsername, userName);
        }
        String userPhone = searchUserRequest.getUserphone();
        if (StringUtils.isNotBlank(userPhone)) {
            queryWrapper.lambda().like(User::getUserphone, userPhone);
        }
        String userAccount = searchUserRequest.getUseraccount();
        if (StringUtils.isNotBlank(userAccount)) {
            queryWrapper.lambda().like(User::getUseraccount, userAccount);
        }
        Integer userRole = searchUserRequest.getUserrole();
        if (userRole != null) {
            queryWrapper.lambda().eq(User::getUserrole, userRole);
        }
        Page<User> page = new Page<>(searchUserRequest.getPageNum(), searchUserRequest.getPageSize());
        Page<User> userPage = this.page(page, queryWrapper);
        ArrayList<UserVo> userVoList = new ArrayList<>();
        userPage.getRecords().forEach(user -> {
            UserVo userVo = new UserVo();
            BeanUtils.copyProperties(user, userVo);
            userVoList.add(userVo);
        });
        Page<UserVo> userVoPage = new Page<>(userPage.getCurrent(), userPage.getSize(), userPage.getTotal());
        userVoPage.setRecords(userVoList);
        return userVoPage;

    }

    @Override
    public Boolean updateUser(UpdateUserRequest updateUserRequest, HttpServletRequest request) throws Exception {
        Integer userid = updateUserRequest.getUserid();
        if (userid == null || userid <= 0) {
            throw new ServiceException(ErrorCode.PARAMS_ERROR);
        }
        if (!isAdmin(request) && !userid.equals(getLoginUser(request).getUserid())) {
            throw new ServiceException(ErrorCode.NO_AUTH);
        }
        User user = userMapper.selectById(userid);
        if (user == null) {
            throw new ServiceException(ErrorCode.PARAMS_ERROR);
        }
        user.setUpdatetime(null);
        BeanUtils.copyProperties(updateUserRequest, user);
        if (updateUserRequest.getUserimage() != null) {
            qiniuUtil.deleteFile(user.getUserimage());
            user.setUserimage(qiniuUtil.upload(updateUserRequest.getUserimage()));
        }

        boolean b = this.updateById(user);
        if (!b) {
            throw new ServiceException(ErrorCode.SYSTEM_ERROR, "更新失败");
        }
        return true;

    }

    @Override
    public int deleteUser(List<Integer> ids, HttpServletRequest request) {
        if (!isAdmin(request)) {
            throw new ServiceException(ErrorCode.NO_AUTH);
        }
        if (ids == null || ids.isEmpty()) {
            throw new ServiceException(ErrorCode.PARAMS_ERROR);
        }
        for (Integer id : ids) {
            User user = userMapper.selectById(id);
            if (user == null) {
                throw new ServiceException(ErrorCode.PARAMS_ERROR);
            }
        }
        return userMapper.deleteBatchIds(ids);
    }
}
